package com.uduemc.biso.node.module.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.github.pagehelper.PageInfo;
import com.uduemc.biso.core.utils.RestResult;
import com.uduemc.biso.node.core.dto.FeignHrepertoryClearByList;
import com.uduemc.biso.node.core.dto.hrepertory.FeignFindInfosByHostIdTypesIds;
import com.uduemc.biso.node.core.entities.HRepertory;
import com.uduemc.biso.node.module.service.HRepertoryService;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

@RestController
@RequestMapping("/h-repertory")
public class HRepertoryController {

	private static final Logger logger = LoggerFactory.getLogger(HRepertoryController.class);

	@Autowired
	private HRepertoryService hRepertoryServiceImpl;

	@PostMapping("/insert")
	public RestResult insert(@Valid @RequestBody HRepertory hRepertory, BindingResult errors) {
		logger.info("insert: " + hRepertory.toString());
		if (errors.hasErrors()) {
			Map<String, Object> message = new HashMap<>();
			for (FieldError fieldError : errors.getFieldErrors()) {
				String field = fieldError.getField();
				String defaultMessage = fieldError.getDefaultMessage();
				message.put(field, defaultMessage);
			}

			return RestResult.error(message);
		}
		HRepertory data = hRepertoryServiceImpl.insert(hRepertory);
		return RestResult.ok(data, HRepertory.class.toString());
	}

	@PutMapping("/update-by-id")
	public RestResult updateById(@Valid @RequestBody HRepertory hRepertory, BindingResult errors) {
		logger.info("updateById: " + hRepertory.toString());
		if (errors.hasErrors()) {
			Map<String, Object> message = new HashMap<>();
			for (FieldError fieldError : errors.getFieldErrors()) {
				String field = fieldError.getField();
				String defaultMessage = fieldError.getDefaultMessage();
				message.put(field, defaultMessage);
			}

			return RestResult.error(message);
		}
		HRepertory findOne = hRepertoryServiceImpl.findOne(hRepertory.getId());
		if (findOne == null) {
			return RestResult.noData();
		}
		HRepertory data = hRepertoryServiceImpl.updateById(hRepertory);
		return RestResult.ok(data, HRepertory.class.toString());
	}

	@GetMapping("/find-one/{id:\\d+}")
	public RestResult findOne(@PathVariable("id") Long id) {
		HRepertory data = hRepertoryServiceImpl.findOne(id);
		if (data == null) {
			return RestResult.noData();
		}
		return RestResult.ok(data, HRepertory.class.toString());
	}

	@GetMapping("/find-by-host-id-and-id/{id:\\d+}/{hostId:\\d+}")
	public RestResult findByHostIdAndId(@PathVariable("id") long id, @PathVariable("hostId") long hostId) {
		HRepertory data = hRepertoryServiceImpl.findByHostIdAndId(id, hostId);
		if (data == null) {
			return RestResult.noData();
		}
		return RestResult.ok(data, HRepertory.class.toString());
	}

	@GetMapping(value = { "/find-all" })
	public RestResult findAll(@PageableDefault(page = 0, size = 12) Pageable pageable) {
		logger.info("pageable: " + pageable.toString());
		List<HRepertory> findAll = hRepertoryServiceImpl.findAll(pageable);
		return RestResult.ok(findAll, HRepertory.class.toString(), true);
	}

	@GetMapping("/delete-by-id/{id:\\d+}")
	public RestResult deleteById(@PathVariable("id") Long id) {
		HRepertory findOne = hRepertoryServiceImpl.findOne(id);
		if (findOne == null) {
			return RestResult.ok();
		}
		hRepertoryServiceImpl.deleteById(id);
		return RestResult.ok(findOne);
	}

	/**
	 * 通过 hostId 获取一个数据库中唯一的 filename
	 * 
	 * @param hostId
	 * @return
	 */
	@GetMapping("/get-uuid-filename/{hostId:\\d+}")
	public RestResult getUUIDFilename(@PathVariable("hostId") long hostId) {
		String uuidFilename = hRepertoryServiceImpl.getUUIDFilename(hostId);
		return RestResult.ok(uuidFilename, String.class.toString());
	}

	/**
	 * 通过条件筛选 hostId,labelId, type, originalFilename 获取数据
	 * 
	 * 通过 page、size 分页
	 * 
	 * 通过 sort 排序
	 * 
	 * @param hostId
	 * @param labelId
	 * @param originalFilename
	 * @param type
	 * @param suffix
	 * @param isRefuse
	 * @param page
	 * @param size
	 * @param sort
	 * @return
	 */
	@PostMapping("/find-by-where-and-page")
	public RestResult findByWhereAndPage(@RequestParam("hostId") long hostId, @RequestParam("labelId") long labelId,
			@RequestParam("originalFilename") String originalFilename, @RequestParam("type") short[] type, @RequestParam("suffix") String[] suffix,
			@RequestParam("isRefuse") short isRefuse, @RequestParam("page") int page, @RequestParam("size") int size, @RequestParam("sort") String sort) {
		PageInfo<HRepertory> restResult = hRepertoryServiceImpl.findByWhereAndPage(hostId, labelId, type, isRefuse, originalFilename, suffix, page, size, sort);
		return RestResult.ok(restResult);
	}

	/**
	 * 通过传入的数组id对资源库中的数据进行修改（放入回收站中）
	 * 
	 * @param id
	 * @return
	 */
	@PostMapping("/delete-by-list")
	public RestResult deleteByList(@RequestBody long[] ids) {
		if (ids.length < 1) {
			return RestResult.error();
		}
		if (!hRepertoryServiceImpl.deleteByList(ids)) {
			return RestResult.error();
		}
		return RestResult.ok(ids);
	}

	/**
	 * 还原资源
	 * 
	 * @param list
	 * @return
	 */
	@PostMapping("/reduction-by-list")
	public RestResult reductionByList(@RequestBody long[] ids) {
		if (ids.length < 1) {
			return RestResult.error();
		}
		if (!hRepertoryServiceImpl.reductionByList(ids)) {
			return RestResult.error();
		}
		return RestResult.ok(ids);
	}

	/**
	 * 还原全部的资源
	 * 
	 * @param hostId
	 * @return
	 */
	@GetMapping("/reduction-all/{hostId:\\d+}")
	public RestResult reductionAll(@PathVariable("hostId") long hostId) {
		boolean reductionAll = hRepertoryServiceImpl.reductionAll(hostId);
		return RestResult.ok(reductionAll, Boolean.class.toString());
	}

	/**
	 * 从硬盘上彻底清除资源
	 * 
	 * @param list
	 * @return
	 */
	@PostMapping("/clear-by-list")
	public RestResult clearByList(@RequestBody FeignHrepertoryClearByList feignHrepertoryClearByList) {
		if (feignHrepertoryClearByList == null || CollUtil.isEmpty(feignHrepertoryClearByList.getRepertoryIds())) {
			return RestResult.error();
		}
		if (!hRepertoryServiceImpl.clearByList(feignHrepertoryClearByList.getRepertoryIds(), feignHrepertoryClearByList.getBasePath())) {
			return RestResult.error();
		}
		return RestResult.ok(feignHrepertoryClearByList.getRepertoryIds());
	}

	/**
	 * 清空当前回收站
	 * 
	 * @param hostId
	 * @return
	 */
	@PostMapping("/clear-all")
	public RestResult clearAll(@RequestParam("hostId") long hostId, @RequestParam("basePath") String basePath) {
		boolean reductionAll = hRepertoryServiceImpl.clearAll(hostId, basePath);
		return RestResult.ok(reductionAll, Boolean.class.toString());
	}

	/**
	 * 通过 hostId 判断请求的 repertoryIds 是否符合
	 * 
	 * @param hostId
	 * @param repertoryIds
	 * @return
	 */
	@PostMapping("/exist-by-host-id-and-repertory-ids")
	public RestResult existByHostIdAndRepertoryIds(@RequestParam("hostId") long hostId, @RequestParam("repertoryIds") List<Long> repertoryIds) {
		boolean bool = hRepertoryServiceImpl.existByHostIdAndRepertoryIds(hostId, repertoryIds);
		return RestResult.ok(bool, Boolean.class.toString());
	}

	/**
	 * 通过 hostId 以及 filePath 获取 HRepertory 数据
	 * 
	 * @param hostId
	 * @param filePath
	 * @return
	 */
	@PostMapping("/find-info-by-host-id-file-path")
	public RestResult findInfoByHostIdFilePath(@RequestParam("hostId") long hostId, @RequestParam("filePath") String filePath) {
		HRepertory findOne = hRepertoryServiceImpl.findInfoByHostIdFilePath(hostId, filePath);
		if (findOne == null) {
			return RestResult.noData();
		}
		return RestResult.ok(findOne);
	}

	/**
	 * 通过 hostId 以及日期和名称获取当天是否存在该文件资源数据 日期 createAt 是时间戳
	 * 
	 * @param hostId
	 * @param repertoryIds
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@PostMapping("/find-by-originalfilename-and-today")
	public RestResult findByOriginalFilenameAndToDay(@RequestParam("hostId") long hostId, @RequestParam("createAt") long createAt,
			@RequestParam("originalFilename") String originalFilename) throws UnsupportedEncodingException {
		if (StrUtil.isBlank(originalFilename)) {
			return null;
		}
		originalFilename = Base64.decodeStr(originalFilename);
		HRepertory findOne = hRepertoryServiceImpl.findByOriginalFilenameAndToDay(hostId, createAt, originalFilename);
		if (findOne == null) {
			return RestResult.noData();
		}
		return RestResult.ok(findOne);
	}

	/**
	 * 通过 条件获取数据总数
	 * 
	 * @param hostId
	 * @param type
	 * @return
	 */
	@PostMapping("/total-type")
	public RestResult totalType(@RequestParam("hostId") long hostId, @RequestParam("type") short type, @RequestParam("isRefuse") short isRefuse) {
		int totalType = hRepertoryServiceImpl.totalType(hostId, type, isRefuse);
		if (totalType < 0) {
			return RestResult.noData();
		}
		return RestResult.ok(totalType);
	}

	/**
	 * 通过传入一个外部链接的数组，生成一个对应数组为key，资源数据为值的 map
	 * 
	 * @param externalLinks
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@PostMapping("/make-external-links")
	public RestResult makeExternalLinks(@RequestParam("hostId") long hostId, @RequestParam("externalLinks") List<String> externalLinks)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		Map<String, HRepertory> resultMap = hRepertoryServiceImpl.makeExternalLinks(hostId, externalLinks);
		return RestResult.ok(resultMap);
	}

	/**
	 * 通过 hostId 获取，绑定SSL证书、且在资源回收站的资源
	 * 
	 * @param hostId
	 * @return
	 * @throws JsonParseException
	 * @throws JsonMappingException
	 * @throws JsonProcessingException
	 * @throws IOException
	 */
	@GetMapping("/infos-by-ssl-in-rsefuse/{hostId:\\d+}")
	public RestResult infosBySslInRsefuse(@PathVariable("hostId") long hostId)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		List<HRepertory> listHRepertory = hRepertoryServiceImpl.infosBySslInRsefuse(hostId);
		return RestResult.ok(listHRepertory, HRepertory.class.toString(), true);
	}

	/**
	 * 通过参数 hostId， types， ids 获取资源数据列表
	 * 
	 * @param hostId
	 * @param types  为空不过滤该字段
	 * @param ids    为空则返回空
	 * @return
	 */
	@PostMapping("/find-infos-by-host-id-types-ids")
	public RestResult findInfosByHostIdTypesIds(@RequestBody FeignFindInfosByHostIdTypesIds findInfosByHostIdTypesIds)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		long hostId = findInfosByHostIdTypesIds.getHostId();
		List<Short> types = findInfosByHostIdTypesIds.getTypes();
		List<Long> ids = findInfosByHostIdTypesIds.getIds();
		return RestResult.ok(hRepertoryServiceImpl.findInfosByHostIdTypesIds(hostId, types, ids), HRepertory.class.toString(), true);
	}
}
